//
// Created by 吴俊颐 on 2025/7/22.
//

#ifndef CIRCUIT_TESTER_HPP
#define CIRCUIT_TESTER_HPP

#include "ui.hpp"


#include <adc.hpp>
#include <array>
#include <climits>
#include <cmath>
#include <fpga.hpp>
#include <delay.hpp>

static  inline constexpr int CHART_POT_NUM = 200;

// 编译期计算频率字
static consteval uint32_t calc_freqWord_compile_time(const uint32_t freq) {
    return static_cast<uint32_t>((4294967295ULL * freq) /25'000'000);
}

// 编译期生成频率表
static consteval  std::array<uint32_t, CHART_POT_NUM> generate_freq_table() {
    std::array<uint32_t, CHART_POT_NUM> table = {};

    // 对数分布的频率点：1K→10K→100K
    constexpr double start = std::log10(1000.0);
    constexpr double end = std::log10(200000.0);
    constexpr double step = (end - start) / (CHART_POT_NUM - 1);

    for (std::size_t i = 0; i < CHART_POT_NUM; ++i) {
        double log_freq = start + i * step;
        table[i] = static_cast<uint32_t>(std::pow(10.0, log_freq));
    }
    return table;
}

// 编译期生成频率字表
static consteval std::array<uint32_t, CHART_POT_NUM> generate_freq_word_table() {
    constexpr auto freq_table = generate_freq_table();
    std::array<uint32_t, CHART_POT_NUM> table = {};

    for (std::size_t i = 0; i < CHART_POT_NUM; ++i) {
        table[i] = calc_freqWord_compile_time(freq_table[i]);
    }
    return table;
}

class CircuitTester
{
    static inline float RIN = 6.666666;
    static inline float ROUT = 6.666666;
    static inline float AMP = 6.666666;
    static inline float FQ = 6.666666;
    static constexpr int DATA_NUM = 400;

    static inline std::array<int16_t, CHART_POT_NUM> amplify_freq_data = {};
    static inline std::array<uint8_t, DATA_NUM> flash_read_data = {};
    static inline std::array<uint8_t, DATA_NUM> flash_write_data = {};
    static inline std::array<int16_t, DATA_NUM * 2> ADC1_DATA = {};
    static inline std::array<int16_t, DATA_NUM> adc1_ch0_data = {};
    static inline std::array<int16_t, DATA_NUM> adc1_ch1_data = {};

    static constexpr int VPP_AVERAGE_NUM = 5;
    static inline std::array<float, VPP_AVERAGE_NUM> vpp_ac_r_in_arr = {};
    static inline int vpp_ac_r_in_index = 0;
    static inline std::array<float, VPP_AVERAGE_NUM> vpp_ac_r_out_arr = {};
    static inline int vpp_ac_r_out_index = 0;
    static inline std::array<float, VPP_AVERAGE_NUM> vpp_ac_none_arr = {};
    static inline int vpp_ac_none_index = 0;
    static inline std::array<float, VPP_AVERAGE_NUM> vpp_dc_r_in_arr = {};
    static inline int vpp_dc_r_in_index = 0;
    static inline std::array<float, VPP_AVERAGE_NUM> vpp_dc_r_out_arr = {};
    static inline int vpp_dc_r_out_index = 0;
    static inline std::array<float, VPP_AVERAGE_NUM> vpp_dc_none_arr = {};
    static inline int vpp_dc_none_index = 0;

    static inline std::array<float, VPP_AVERAGE_NUM> vpp_dc = {};
    static inline float vpp_ac_r_in = 0.0f;
    static inline float vpp_ac_r_out = 0.0f;
    static inline float vpp_ac_none = 0.0f;
    static inline float vpp_dc_r_in = 0.0f;
    static inline float vpp_dc_r_out = 0.0f;
    static inline float vpp_dc_none = 0.0f;

    using R_IN_pin = hal::gpio::portA::pin8;
    using R_OUT_pin = hal::gpio::portA::pin11;
    using AC_DC_pin = hal::gpio::portA::pin12;
    using adc = hal::adc1;

    template<typename T, std::size_t size>
    static auto find_vpp(std::array<T, size>& arr)
    {
        T max = arr[0], min = arr[0];
        for (const T val: arr) {
            if (val > max) max = val;
            if (val < min) min = val;
        }
        T vpp = max - min;
        return vpp;
    }

    template<typename T, std::size_t size>
static auto find_max(std::array<T, size>& arr)
    {
        T max = arr[0];
        std::size_t index = 0;
        for (std::size_t i=0;i<size;++i) {
            if (arr[i] > max) {
                max = arr[i];
                index = i;
            }
        }
        return std::make_pair(max,index);
    }


    template<typename T, std::size_t size>
    static auto find_max_min(std::array<T, size>& arr)
        {
            T max = arr[0], min = arr[0];
            for (const T val: arr) {
                if (val > max) max = val;
                if (val < min) min = val;
            }
            return std::make_pair(max,min);
        }



    static float find_vpp_ac(std::array<float, VPP_AVERAGE_NUM> &vpp_arr, int &index)
    {
        // 计算通道0:AC 的峰峰值 (Vpp)
        vpp_arr[index % VPP_AVERAGE_NUM] = find_vpp(adc1_ch0_data);// 存储峰峰值

        // 更新环形缓冲区索引
        if (index < INT_MAX) { index = (index + 1); }
        else { index = VPP_AVERAGE_NUM; }

        // ---------- 滑动平均滤波 ----------
        if (index < VPP_AVERAGE_NUM)
            return vpp_arr[index - 1];

        float sum_ac = 0.0f;
        // 缓冲区未满时，只计算有效数据
        for (size_t i = 0; i < VPP_AVERAGE_NUM; ++i) { sum_ac += vpp_arr[i]; }
        return sum_ac / static_cast<float>(VPP_AVERAGE_NUM);
    }


    static auto find_dc_avg()
    {
        int sum = 0;
        for (const auto &value: adc1_ch1_data) { sum += value; }
        return static_cast<float>(sum) / static_cast<float>(DATA_NUM);
    }

    static void calculate_param()
    {
        constexpr float r_gain = 2.39521f;
        RIN = (2000.0f * vpp_ac_r_in) / (vpp_ac_none - vpp_ac_r_in);
        ROUT = (vpp_ac_none - vpp_ac_r_out) / vpp_ac_r_out * 3980.0f * r_gain;
        AMP = vpp_ac_none *0.1f;// 1000mV / 0.01V
    }

    static void switch_AC() { AC_DC_pin::clear(); }
    static void switch_DC() { AC_DC_pin::set(); }

    static void switch_R_IN_mode()
    {
        R_IN_pin::clear();
        R_OUT_pin::set();
    }

    static void switch_R_NONE_mode()
    {
        R_IN_pin::set();
        R_OUT_pin::set();
    }

    static void switch_R_OUT_mode()
    {
        R_IN_pin::set();
        R_OUT_pin::clear();
    }

    // freq/25M = freq_word/2^32 → freq_word = 2^32 * freq/25M

     static auto calc_freqWord(const uint32_t freq)
    {
        return 4294967295 * freq / 25000000;
    }

public:
    static void init()
    {
        R_IN_pin cfg1;
        R_OUT_pin cfg2;
        AC_DC_pin cfg3;
        cfg1.initializer().mode.output().pull.none().speed.very_high();
        cfg2.initializer().mode.output().pull.none().speed.very_high();
        cfg3.initializer().mode.output().pull.none().speed.very_high();

        FPGA::RESET();
        setFreq_DAC(1000,171799);// 1KHz

        adc::init();
        adc::set_sample_rate(FREQ_84M_to_100K);
        bsp::m25p16::control::init();
        // switch_AC();
    }


    static auto &get_amplify_freq() { return amplify_freq_data; }
    static auto &get_flash_write_data() { return flash_write_data; }
    static auto &get_flash_read_data() { return flash_read_data; }


    static void measure_adc(uint32_t delay_ms)
    {
        core::delay::ms(delay_ms);
        adc::start(ADC1_DATA);


        // 获取当前系统tick作为起始时间
        constexpr uint32_t timeout_ms = 1000;
        const uint32_t start_tick = osKernelGetTickCount();

        // 轮询等待采样完成（带超时检测）
        while (!hal::adc1::getDMAComplete()) {
            // 检查是否超时
            if (osKernelGetTickCount() - start_tick > timeout_ms) {
                adc::stop();
                return;
            }
            core::delay::ms(1);  // 短暂延迟避免CPU占用
        }

        // 处理新到达的数据
        for (int i = 0; i < DATA_NUM; ++i) {
            adc1_ch0_data[i] = ADC1_DATA[i * 2];
            adc1_ch1_data[i] = ADC1_DATA[i * 2 + 1];
        }
    }

    static void setFreq_DAC(const uint32_t freq, const uint32_t freq_word)
    {
        using namespace FPGA;
        constexpr uint32_t cycles = 10;
        constexpr uint32_t sample_rate = 60;

        const uint32_t freq_sample = freq*60;
        fpga_info::freq_word::write(freq_word);
        fpga_info::div::write(100'000'000/(freq_sample)-1);
        fpga_info::counter::write(sample_rate*cycles);//   计数10个脉冲周期
        fpga_info::state_flag::write(0x01);// 开启ADC
    }
    static auto getVpp()
    {
        using namespace FPGA;
        fpga_info::state_flag::write(0x00);// 关闭ADC
        return fpga_info::vpp::read();
    }

    // 异步测量基本参数
    static void measure_base_param()
    {
        using namespace core;
        using namespace gui::interface;
        using namespace FPGA;
        // 交流补偿增益
        constexpr float ac_gain = 1.2f;
        constexpr float adc_to_mV = 3300.0f / 4095.0f;
        constexpr uint32_t delay_ms[3] = {500, 300, 900};
        //设置为1KHZ的信号
        fpga_info::freq_word::write(171799);// 1KHz
        //ADC1通道0是AC
        switch_AC();

        //前端负载接上时采AC
        switch_R_IN_mode();
        measure_adc(delay_ms[0]);
        vpp_ac_r_in = static_cast<float>(getVpp())* ac_gain * adc_to_mV;

        //空载时采AC
        switch_R_NONE_mode();
        measure_adc(delay_ms[1]);
        vpp_ac_none = static_cast<float>(getVpp()) * ac_gain * adc_to_mV;

        //后端负载接上时采AC
        switch_R_OUT_mode();
        measure_adc(delay_ms[2]);
        vpp_ac_r_out = static_cast<float>(getVpp()) * ac_gain * adc_to_mV;

        if (CCT::get_generate_state()) {
            //计算参数（输入电阻，输出电阻，增益）
            calculate_param();
            CCT::generate_text(RIN, ROUT, AMP, FQ);
        }else {
            CCT::clear_text();
        }
    }



    // 编译期常量表
    static constexpr auto FREQ_TABLE = generate_freq_table();
    static constexpr auto FREQ_WORD_TABLE = generate_freq_word_table();

    // 异步扫频
    static void sweep_freq()
    {
        using namespace gui::interface;
        // 静态计数器，用于跟踪当前扫描位置（保留值在函数调用之间）
        // 注意：点索引需按对数分布（低频密集，高频稀疏）
        static uint32_t index = 0;

        // 1. 准备阶段：切换到空载测试模式（断开被测电路）
        switch_R_NONE_mode();
        // 计算当前要测试的频率点索引（循环使用数组空间）
        auto real_index = index % CHART_POT_NUM;

        // 2. 设置当前测试频率
        // 使用编译期生成的常量表
        // 直接使用预计算的频率字 使用频率表设置采样率
        setFreq_DAC(FREQ_TABLE[real_index], FREQ_WORD_TABLE[real_index]);
        // setFreq_DAC(FREQ_TABLE[0], FREQ_WORD_TABLE[0]);


        // 3. 信号测量：等待稳定后获取ADC采样值
        // 测试表明90ms延迟可避免毛刺（50ms有干扰，80 100ms稳定）
        measure_adc(90);

        // const auto verify = fpga_info::self()->verify;
        // amplify_freq_data[real_index] = verify;

        // 4. 获取并记录当前频率的信号幅度
        const auto vpp = getVpp();
        amplify_freq_data[real_index] = vpp;

        // 5. 更新显示范围：确保Y轴至少有0-31的显示范围
        auto [max,_] = find_max_min(amplify_freq_data);
        max |= 0x1F;

        // 6. 更新扫描位置：循环递增直到覆盖所有点
        if (index < UINT_MAX) {index = (index + 1); }
        else { index = CHART_POT_NUM; }

        // 7. 周期性的UI更新（每8个点更新一次）
        // 位运算: index & 0x07 == 0 等效于 index % 8 == 0
        if ((index & 0x07) == 0) {
            CCT::setChartRange(0,max);
            CCT::generate_data(amplify_freq_data);
        }

        // 8. 更新进度显示（实时显示已扫描点数）
        if (index<=CHART_POT_NUM)
            CCT::setChartPoints(index);

        // 9. 扫频完成后计算截止频率（-3dB点）
        // 条件：完成扫频 且 处于8的倍数更新周期 同步UI刷新周期
        if (index>=CHART_POT_NUM && (index & 0x07) == 0) {
            auto real_index_fc = 0;
            auto index_fc = 0;
            // 9.1 找到最大响应值 显示上限频率
            auto [threshold_value,max_index] = find_max(amplify_freq_data);
            // 9.2 计算-3dB阈值（0.707 ≈ 1/sqrt(2)）
            threshold_value *= 0.707f;

            for (std::size_t i = max_index; i < CHART_POT_NUM-1; ++i) {
                if (amplify_freq_data[i]<threshold_value) {
                    if(amplify_freq_data[i]>  amplify_freq_data[i+1]) {
                        index_fc=i;
                        break;
                    }
                }
            }

            auto diff =threshold_value- (amplify_freq_data[index_fc]+amplify_freq_data[index_fc+1])/2;
            // 判断那个索引的幅度离门槛值近
            if (diff) {
                real_index_fc=index_fc;
            }
            else {
                real_index_fc=index_fc+1;
            }
            CCT::generate_fc_text(FREQ_TABLE[real_index_fc]);
        }
    }
    static void judge_bug_type()
    {
        using namespace core;
        using namespace gui::interface;
        using namespace FPGA;
        // 交流补偿增益
        constexpr float ac_gain = 1.2f;
        // 直流补偿增益
        constexpr float dc_gain = 1.0;
        constexpr float adc_to_mV = 3300.0f / 4095.0f;
        constexpr uint32_t delay_ms[3] = {500, 300, 900};
        // 通过判断确定bug_id
        static uint8_t bug_id = 1;
        adc::set_sample_rate(FREQ_84M_to_100K);


        //设置为1KHZ的信号
        fpga_info::freq_word::write(171799);// 1KHz
        //ADC1通道0是AC
        switch_AC();
        delay::ms(500);
        //空载时采AC
        switch_R_NONE_mode();
        measure_adc(delay_ms[1]);
        vpp_ac_none = static_cast<float>(getVpp()) * ac_gain * adc_to_mV;

        //ADC1通道0是DC
        switch_DC();
        delay::ms(500);

        //空载时采DC
        switch_R_NONE_mode();
        measure_adc(delay_ms[1]);
        vpp_dc_none = find_dc_avg() * dc_gain * adc_to_mV;

        delay::ms(100);

        // 电压分类决策树（粗分版）
        if (vpp_dc_none >= 1000 && vpp_dc_none <= 1300) {
            // 电容相关故障/正常状态分支

            if (vpp_ac_none < 100) {
                bug_id = 6;  // C1/C3断路（电压特征接近）
            }
            else if (vpp_ac_none < 700) {
                bug_id = 1;  // 正常或电容放大（需后续细分）
            }
            else
            {
                bug_id = 7;  // C2断路
            }
        }
        else {
            // 电阻故障分支（所有AC<200）
            if (vpp_dc_none >= 2000) {
                bug_id = 9; // 高阻短路(R1/R3短)
            }
            else if (vpp_dc_none >= 1800) {
                bug_id = 2;  // 中高阻异常(R1断/R4断/R2短)
            }
            else if (vpp_dc_none >= 600) {
                bug_id = 3;  // R2断
            }
            else if (vpp_dc_none < 50) {
                bug_id = 4;  // 低阻故障(R3断/R4短)
            }
        }
        CCT::generate_bug_text(bug_id);
    }
};

#endif //CIRCUIT_TESTER_HPP